'''
@name: Script Python GeoLoc
@author: Quentin Lamotte, Remi Ognard, Arva Fidahoussen
@verion: 1.0
'''

# IMPORTATIONS NECESSAIRES AU FONCTIONNEMENT DE CE SCRIPT

import yaml
import sqlite3
from geopy import geocoders
import random
import unicodedata




# FONCTIONS DE CONNEXION ET DECONNEXION A LA BASE DE DONNEES

def seConnecter(leFichierBDD):
	return sqlite3.connect(leFichierBDD)

def seDeconnecter(laConnexion):
	laConnexion.close()



# FONCTION PERMETTANT DE FORMATER L'ADRESSE AFIN QU'ELLE PUISSE DONNER LE MEILLEUR RESULTAT POSSIBLE

def supprimerPartiesInutiles(laChaine):
	try:
		leCPVille = laChaine.split("-")
		leCPVille.reverse()
		return str(leCPVille[0])
	except Exception:
		return laChaine


# FONCTION PERMETTANT DE RECUPERER TOUTES LES ADRESSES

def obtenirListeAdresses(leCurseur):
	laListeAdresse = []
	lIncrem = 0
	uneAdresse = ""
	leCurseur.execute("SELECT id, rank, parserank, data FROM ISIC1_1 ORDER BY id ASC, rank ASC, parserank DESC")
	lesAdresses = leCurseur.fetchall()
	for unId, unRank, unParserank, uneData in lesAdresses:
		if(unParserank == 0):
			if(lIncrem == 0):
				uneAdresse = supprimerPartiesInutiles(uneData).replace(".", "").replace(",", "").replace(";", "")
			else:
				if(lIncrem<3):
					uneAdresse = supprimerPartiesInutiles(uneData).replace(".", "").replace(",", "").replace(";", "") + " " + uneAdresse
			unChamp = [unId, unRank, uneAdresse.strip()]
			laListeAdresse.append(unChamp)
			lIncrem = 0
		else:
			if(lIncrem == 0):
				uneAdresse = supprimerPartiesInutiles(uneData).replace(".", "").replace(",", "").replace(";", "")
				lIncrem = lIncrem + 1
			else:
				if(lIncrem<3):
					uneAdresse = supprimerPartiesInutiles(uneData).replace(".", "").replace(",", "").replace(";", "") + " " + uneAdresse
					lIncrem = lIncrem + 1
	return laListeAdresse



# FONCTION PERMETTANT D'OBTENIR UN JEU DE TEST

def obtenirJeuTest(laListe, leNombreAdresses):
	laListeJeuTest = []
	laTailleListe = len(laListe)
	leNombreAleatoire = random.randint(0, laTailleListe - 1 - leNombreAdresses)
	for indice in range(leNombreAleatoire, leNombreAleatoire + leNombreAdresses):
		laListeJeuTest.append(laListe[indice])
	return laListeJeuTest



# FONCTION PERMETTANT DE LOCALISER UNE ADRESSE

def utiliserGoogleV3(lAdresse):
	try:
		leGeolocaliseur = geocoders.GoogleV3()
		leResultat = leGeolocaliseur.geocode(lAdresse, exactly_one = False)
		leNombreReponses = len(leResultat)
		leNombreAleatoire = random.randint(0, leNombreReponses - 1)
		laPlace, (laLat, laLon) = leResultat[leNombreAleatoire]
		return [laPlace, laLon, laLat]
	except Exception:
		return ""



# FONCTIONS PERMETTANT DE REMPLIR LA TABLE LISTE_ADRESSE EN GEOLOCALISANT LES ADRESSES

def remplirTableLocalisation(leCurseur, lId, leRank, lAdresse, laPlace, laLongitude, laLatitude):
	leCurseur.execute('INSERT INTO LISTE_ADRESSE VALUES(' + lId + ', ' + leRank + ', "' + lAdresse + '", "' + laPlace + '",' + laLongitude + ', ' + laLatitude + ')')

def obtenirLocalisation(leCurseur, laListe):
	leCurseur.execute("DELETE FROM LISTE_ADRESSE")
	for uneAdresse in laListe:
		uneLocalisation = utiliserGoogleV3(uneAdresse)
		if(uneLocalisation == ""):
			remplirTableLocalisation(leCurseur, str(uneAdresse[0]), str(uneAdresse[1]), str(uneAdresse[2]), "NOT FOUND", "NULL", "NULL")
		else:
			remplirTableLocalisation(leCurseur, str(uneAdresse[0]), str(uneAdresse[1]), uneAdresse[2], uneLocalisation[0], str(uneLocalisation[1]), str(uneLocalisation[2]))



# FONCTION PERMETTANT DE RECUPERER LES ADRESSES LOCALISEES PONDEREES

def obtenirListePosition(leCurseur):
	laListePosition = []
	leCurseur.execute("SELECT place, lon, lat, count(*) FROM LISTE_ADRESSE WHERE lon IS NOT NULL AND lat IS NOT NULL GROUP BY place, lon, lat")
	lesLocalisations = curseur.fetchall()
	for unePlace, uneLon, uneLat, unCompteur in lesLocalisations:
		laListePosition.append([unePlace, uneLon, uneLat, unCompteur])
	return laListePosition



# FONCTION PERMETTANT D'ECRIRE UN FICHIER JSON RECUPERABLE PAR KARTOGRAPH

def formatJSON(lAdresse):
	return u'{ "name": "' + lAdresse[0] + '", "lon": ' + str(lAdresse[1]) + ', "lat": ' + str(lAdresse[2]) + ', "radius": ' + str(lAdresse[3]) + ' }'

def ecrireJSON(leFichierJSON, laListe):
	file(leFichierJSON, "w")
	leFichier = open(leFichierJSON, "a")
	leFichier.write("[")
	leNumeroAdresse = 0
	for uneAdresse in laListe:
		uneLocalisation = formatJSON(uneAdresse)
		if(leNumeroAdresse == 0):
			leFichier.write(unicodedata.normalize('NFKD', uneLocalisation).encode('ascii','ignore'))
		else:
			leFichier.write(",\n" + unicodedata.normalize('NFKD', uneLocalisation).encode('ascii','ignore'))
		leNumeroAdresse = leNumeroAdresse + 1
	leFichier.write("]")
	leFichier.close()



# FONCTION PERMETTANT D'ECRIRE UN FICHIER LOG CONTENANT LES RESULTATS DE GEOLOCALISATION

def ecrireLOG(leFichierLOG, leCurseur):
	file(leFichierLOG, "w")
	leFichier = open(leFichierLOG, "a")
	leCurseur.execute("SELECT id, rank, adresse, place, lon, lat FROM LISTE_ADRESSE")
	lesAdressesTesteesLocalisees = curseur.fetchall()
	for unId, unRank, uneAdresse, unePlace, uneLon, uneLat in lesAdressesTesteesLocalisees:
		leFichier.write(str(unId) + " - " + str(unRank) + " - " + unicodedata.normalize('NFKD', uneAdresse).encode('ascii','ignore') + " - " + unicodedata.normalize('NFKD', unePlace).encode('ascii','ignore') + " - " + str(uneLon) + " - " + str(uneLat) + "\n")
	leFichier.close()



# FONCTION PERMETTANT DE DONNER LE POURCENTAGE DE REUSSITE

def afficherPourcentage(leCurseur, leNombreAdresses):
	leCurseur.execute("SELECT count(*) FROM LISTE_ADRESSE WHERE lon IS NOT NULL AND lat IS NOT NULL")
	leNombreReussites = curseur.fetchall()
	for leCompteur in leNombreReussites:
		print(str(leCompteur) + " sur un total de " + str(leNombreAdresses) + ".\n")





# RECUPERATION DES CONSTANTES DANS LE FICHIER DE PARAMETRAGE YAML

fluxYAML = open("param.yaml", "r")
parametres = yaml.load(fluxYAML)
fichierBDD = yaml.dump(parametres['fichierBDD']).replace("\n...\n","")
fichierJSON = yaml.dump(parametres["fichierJSON"]).replace("\n...\n","")
fichierLOG = yaml.dump(parametres["fichierLOG"]).replace("\n...\n","")
nombreAdresses = int(yaml.dump(parametres["nombreAdresses"]).replace("\n...\n",""))
fluxYAML.close()


# ALGORITHME PRINCIPAL

connexion = seConnecter(fichierBDD)
curseur = connexion.cursor()
print("\nRecuperation des adresses...")
listeAdresses = obtenirListeAdresses(curseur)
if(nombreAdresses <= 0 or nombreAdresses > len(listeAdresses)):
	nombreAdresses = len(listeAdresses)
	print("\nParametre nombreAdresses modifie a : " + str(nombreAdresses))
print("\nEtablissement d'un jeu de test...")
listeJeuTest = obtenirJeuTest(listeAdresses, nombreAdresses)
print("\nEnvoi de la requete a Geopy et stockage dans la BDD...")
obtenirLocalisation(curseur, listeJeuTest)
print("\nRecuperation des adresses localisees avec ponderation...")
listePosition = obtenirListePosition(curseur)
print("\nEcriture du fichier JSON...")
ecrireJSON(fichierJSON, listePosition)
print("\nEcriture du fichier LOG...")
ecrireLOG(fichierLOG, curseur)
print("\nAffichage du pourcentage de reussite :")
afficherPourcentage(curseur, nombreAdresses)
seDeconnecter(connexion)
